<?php
namespace Teemo\Db;

use Teemo\Core\Log;

use Swoole\Coroutine\MySQL as SwMySQL;

/**
 * Created by PhpStorm.
 * User: lkk
 * Date: 2019/1/11
 * Time: 6:30 PM
 */
class Mysql
{


    private $config;    //数据库配置

    private $master;    //主数据库连接

    private $slave;     //从数据库连接list

    // 连接
    public function connect($config)
    {

        //创建主数据连接
        $master = new SwMySQL();
        $res    = $master->connect($config['master']);
        if ($res == false) {
            // 连接失败，抛出异常
            throw new \Exception($master->error, $master->errno);
        } else {
            $this->master = $master;
        }

        //创建从数据库连接
        foreach ($config['slave'] as $conf) {
            $slave = new SwMySQL();
            $res   = $slave->connect($conf);
            if ($res == false) {
                // 连接失败，抛出异常
                throw new \Exception($slave->error, $slave->errno);
            } else {
                $this->slave[] = $slave;
            }
        }

        $this->config = $config;

        return $res;
    }

    /*
     * 单个数据库重连
     * */
    public function reconnect($type, $index)
    {

        // 主重连
        if ($type == 'master') {
            $master = new SwMySql();
            $res    = $master->connect($this->config['master']);
            if ($res == false) {
                // 连接失败，抛出异常
                throw new \Exception($master->error, $master->errno);
            } else {
                $this->master = $master;
            }
            return $this->master;
        }

        // 从重连
        if ($type == 'slave') {
            $slave = new SwMySql();
            $res   = $slave->connect($this->config['slave'][$index]);
            if ($res == false) {
                // 连接失败，抛出异常
                throw new \Exception($slave->error, $slave->errno);
            } else {
                $this->slave[$index] = $slave;
            }
            return $slave;
        }
    }


    /**
     * @param $sql
     *
     * @desc 根据sql语句，选择主还是从
     *       @ 判断有select 则选择从库， insert, update, delete等选择主库
     * @return array
     */
    protected function chooseDb($sql)
    {
        // 查询语句
        if ('select' == strtolower(substr(trim($sql), 0, 6))) {
            $index = 1 == count($this->slave) ? 0 : array_rand($this->slave);
            return ['type' => 'slave', 'index' => $index, 'db' => $this->slave[$index],];
        }

        // 其他
        return ['type' => 'master', 'index' => 0, 'db' => $this->master,];
    }


    /**
     * @param $result
     * @param $db MySQL
     *
     * @return array
     * @desc 格式化返回结果：查询：返回结果集，插入：返回新增id, 更新删除等操作：返回影响行数
     */
    public function parseResut($result, $db)
    {

        if ($result === true) {
            return ['affected_rows' => $db->affected_rows, 'insert_id' => $db->insert_id,];
        }
        return $result;
    }

    /*
     * @param $name
     * @param $arguments
     * @return mixed
     * @desc 利用__call,实现操作mysql,并能做断线重连等相关检测
     * */
    public function __call($name, $arguments)
    {
        $sql = $arguments[0];
        $res = $this->chooseDb($sql);
        echo '当前操作实例：' . $res['type'] . ':' . $res['index'] . "[INFO]" . $res['db']->serverInfo['host'] . ':' . $res['db']->serverInfo['port'] . PHP_EOL;
        $db = $res['db'];

        $result = $db->$name($sql);
        Log::info($sql);
        if (false === $result) {
            Log::warning('mysql query false', [$sql]);
            if (!$db->connected) {
                $this->reconnect($res['type'], $res['index']);
                $result = $db->$name($sql);
            }
            if (!empty($db->errno)) {//有错误码，则抛出弃常
                throw new \Exception($db->error, $db->errno);
            }
        }
        return $this->parseResut($result, $db);
    }

    /**
     * @return mixed
     * @desc 返回配置信息
     */
    public function getConfig()
    {
        return $this->config;
    }
}